#include <buola/chart/plots/cscatterplot.h>

#include <buola/image/cgc.h>
#include <buola/chart/cxychart.h>
#include <buola/chart/cxaxis.h>
#include <buola/chart/cyaxis.h>

namespace buola { namespace chart {

CScatterPlot::CScatterPlot()
    :   mPointColor(std::wstring(L"black")),
        mPointFillColor(std::wstring(L"orangered")),
        mPointDiameter(8.0),
        mPointShape(CIRCLE)
{
    mStyle=POINTFILL;
}

CScatterPlot::~CScatterPlot()
{
}

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
////////////////////////// Interface //////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

void CScatterPlot::SetSeries(PSeries pSeries)
{
    mSeries=pSeries;
}

void CScatterPlot::SetColor(const img::CColor &pColor)
{
    mPointColor=pColor;
    mPointFillColor=pColor;
    mPointFillColor.a=0.3;
}

void CScatterPlot::SetPointColor(const img::CColor &pColor)
{
    mPointColor=pColor;
}

void CScatterPlot::SetPointDiameterSeries(PSeries pSeries)
{
    mDiameterSeries=pSeries;

    if(mDiameterSeries.get()&&!mDiameterMapper.get())
    {
        mDiameterMapper.reset(new ELinearMapper<double,double>(0.0,1.0,0.0,1.0));
    }
}

void CScatterPlot::SetPointDiameterMapper(EValueMapper<double,double> *pMapper)
{
    mDiameterMapper.reset(pMapper);
}

void CScatterPlot::SetPointDiameter(double pDiameter)
{
    mPointDiameter=pDiameter;
}

void CScatterPlot::SetPointFillColorSeries(PSeries pSeries)
{
    mColorSeries=pSeries;

    if(mColorSeries.get()&&!mColorMapper.get())
    {
        mColorMapper.reset(new ELinearMapper<double,img::CColor>(0.0,50.0,img::CColor(0,0,0),img::CColor(1,1,1)));
    }
}

void CScatterPlot::SetPointFillColorMapper(EValueMapper<double,img::CColor> *pMapper)
{
    mColorMapper.reset(pMapper);
}

void CScatterPlot::SetPointFillColor(const img::CColor &pColor)
{
    mPointFillColor=pColor;
}

void CScatterPlot::SetPointShape(ePointShape pShape)
{
    mPointShape=pShape;
}

CRect_d CScatterPlot::GetExtraSpace()
{
    double lMax=mPointDiameter;

    if(mDiameterSeries.get())
    {
        lMax=mDiameterMapper->Map(mDiameterSeries->mMax.y);
    }

    return CRect_d(lMax,lMax,lMax,lMax);
}

void CScatterPlot::Draw(CXYChartContext &pC)
{
    if(!mSeries->size()) return;

    SPointDrawer lDrawer(pC.mGC,mPointShape,mStyle|POINTS);
    lDrawer.SetDiameter(mPointDiameter);
    lDrawer.SetColor(mPointColor);
    lDrawer.SetFillColor(mPointFillColor);
    lDrawer.SetLineWidth(1.0);
    for(int j=0;j<mSeries->size();j++)
    {
        if(mDiameterSeries.get())
        {
            lDrawer.SetDiameter(mDiameterMapper->Map(
                        mDiameterSeries->GetY(j)));
        }
        if(mColorSeries.get())
        {
            lDrawer.SetFillColor(mColorMapper->Map(
                        mColorSeries->GetY(j)));
        }

        lDrawer.Draw(CPoint_d(pC.mXAxis->Map(mSeries->GetX(j)),
                     pC.mYAxis->Map(mSeries->GetY(j))));
    }
}

double CScatterPlot::GetDist(const CPoint_d &pPos,CXAxis *pXAxis,CYAxis *pYAxis)
{
    if(GetNearestPoint(pPos,pXAxis,pYAxis).Undefined())
        return INFINITY;
    return 0;
}

CPoint_d CScatterPlot::GetNearestPoint(const CPoint_d &pPos,CXAxis *pXAxis,CYAxis *pYAxis)
{
    for(int j=mSeries->size()-1;j>=0;j--)
    {
        CPoint_d lPoint(pXAxis->Map(mSeries->GetX(j)),
                      pYAxis->Map(mSeries->GetY(j)));

        double lDiameter=mDiameterSeries.get()?mDiameterMapper->Map(
                                mDiameterSeries->GetY(j)):mPointDiameter;

        if(dist(lPoint,pPos)<lDiameter/2)
        {
            return CPoint_d(mSeries->GetX(j),mSeries->GetY(j));
        }
    }

    return CPoint_d(nUndefined);
}

/*namespace chart*/ } /*namespace buola*/ }
